package com.hitomi.smlibrary;

import ohos.agp.components.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by hitomi on 2016/9/18. <br/>
 * <p>
 * github : https://github.com/Hitomis <br/>
 * <p>
 * email : 196425254@qq.com
 */
public class SpinMenu extends StackLayout implements Component.TouchEventListener, Component.LayoutRefreshedListener {

    static final String TAG = "SpinMenu";

    static final String TAG_ITEM_CONTAINER = "tag_item_container";

    static final int TAG_ITEM_CONTAINER_ID = 0xffbb00;

    static final String TAG_ITEM_PAGER = "tag_item_pager";

    static final int TAG_ITEM_PAGER_ID = 0xffbb01;

    static final String TAG_ITEM_HINT = "tag_item_hint";

    static final int TAG_ITEM_HINT_ID = 0xffbb02;

    static final int MENU_STATE_CLOSE = -2;

    static final int MENU_STATE_CLOSED = -1;

    static final int MENU_STATE_OPEN = 1;

    static final int MENU_STATE_OPENED = 2;

    /**
     * 左右菜单 Item 移动动画的距离
     */
    static final float TRAN_SKNEW_VALUE = 160;

    /**
     * Hint 相对 页面的上外边距
     */
    static final int HINT_TOP_MARGIN = 15;

    /**
     * 可旋转、转动布局
     */
    private SpinMenuLayout spinMenuLayout;

    /**
     * 菜单打开关闭动画帮助类
     */
    private SpinMenuAnimator spinMenuAnimator;

    /**
     * 页面适配器
     */
    private PageSliderProvider pagerAdapter;

    /**
     * 菜单状态改变监听器
     */
    private OnSpinMenuStateChangeListener onSpinMenuStateChangeListener;

    /**
     * 缓存 Fragment 的集合，供 {@link #pagerAdapter} 回收使用
     */
    private List pagerObjects;

    /**
     * 菜单项集合
     */
    private List<SMItemLayout> smItemLayoutList;

    /**
     * 页面标题字符集合
     */
    private List<String> hintStrList;

    /**
     * 页面标题字符尺寸
     */
    private int hintTextSize = dp2px(14);

    /**
     * 页面标题字符颜色
     */
    private int hintTextColor = 0xff666666;

    /**
     * 默认打开菜单时页面缩小的比率
     */
    private float scaleRatio = .36f;

    /**
     * 控件是否初始化的标记变量
     */
    private boolean init = true;

    /**
     * 是否启用手势识别
     */
    private boolean enableGesture;

    /**
     * 当前菜单状态，默认为已关闭
     */
    private int menuState = MENU_STATE_CLOSED;

    /**
     * 当前菜单状态更新时间，防止动画卡死bug特别计算
     */
    private long menuStateUpdateTime;

    private GestureDetector gestureDetector;

    /**
     * 滑动与触摸之间的阀值
     */
    private int touchSlop = 8;

    private OnSpinSelectedListener onSpinSelectedListener = new OnSpinSelectedListener() {
        @Override
        public void onSpinSelected(int position) {
        }
    };

    private OnMenuSelectedListener onMenuSelectedListener = new OnMenuSelectedListener() {
        @Override
        public void onMenuSelected(SMItemLayout smItemLayout) {
            closeMenu(smItemLayout);
        }
    };

    public SpinMenu(Context context) {
        this(context, null);
    }

    public SpinMenu(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public SpinMenu(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);

        scaleRatio = AttrUtils.getFloatFromAttr(attrs, "scale_ratio", scaleRatio);
        hintTextSize = AttrUtils.getDimensionFromAttr(attrs, "hint_text_size", hintTextSize);
        hintTextColor = AttrUtils.getColorFromAttr(attrs, "hint_text_color", hintTextColor);

        pagerObjects = new ArrayList();
        smItemLayoutList = new ArrayList<>();

        final int smLayoutId = 0x6F060505;
        ComponentContainer.LayoutConfig layoutParams = new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        spinMenuLayout = new SpinMenuLayout(getContext());
        spinMenuLayout.setId(smLayoutId);
        spinMenuLayout.setLayoutConfig(layoutParams);
        spinMenuLayout.setOnSpinSelectedListener(onSpinSelectedListener);
        spinMenuLayout.setOnMenuSelectedListener(onMenuSelectedListener);
        addComponent(spinMenuLayout);
        setTouchEventListener(this);
        setLayoutRefreshedListener(this);
        gestureDetector = new GestureDetector(context, menuGestureListener);
    }

    private GestureDetector.SimpleOnGestureListener menuGestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onScroll(TouchEvent e1, TouchEvent e2, float distanceX, float distanceY) {
            if (Math.abs(distanceX) < touchSlop && distanceY < -touchSlop * 3) {
                openMenu();
            }
            return true;
        }
    };


    public void setFragmentAdapter(PageSliderProvider adapter) {
        if (pagerAdapter != null) {
            pagerAdapter.startUpdate(spinMenuLayout);
            for (int i = 0; i < adapter.getCount(); i++) {
                ComponentContainer pager = (ComponentContainer) spinMenuLayout.getComponentAt(i).findComponentById(TAG_ITEM_PAGER_ID);
                pagerAdapter.destroyPageFromContainer(pager, i, pagerObjects.get(i));
            }
            pagerAdapter.onUpdateFinished(spinMenuLayout);
        }

        int pagerCount = adapter.getCount();
        if (pagerCount > spinMenuLayout.getMaxMenuItemCount())
            throw new RuntimeException(String.format("Component number can't be more than %d", spinMenuLayout.getMaxMenuItemCount()));

        pagerAdapter = adapter;

        SMItemLayout.LayoutConfig itemLinLayParams = new SMItemLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        DirectionalLayout.LayoutConfig containerLinlayParams = new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        StackLayout.LayoutConfig pagerFrameParams = new StackLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        DirectionalLayout.LayoutConfig hintLinLayParams = new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        hintLinLayParams.setMarginTop(HINT_TOP_MARGIN);
        pagerAdapter.startUpdate(spinMenuLayout);
        for (int i = 0; i < pagerCount; i++) {
            // 创建菜单父容器布局
            SMItemLayout smItemLayout = new SMItemLayout(getContext());
            smItemLayout.setId(i + 1);
            smItemLayout.setAlignment(LayoutAlignment.CENTER);
            smItemLayout.setLayoutConfig(itemLinLayParams);

            // 创建包裹StackLayout
            StackLayout frameContainer = new StackLayout(getContext());
            frameContainer.setTag(TAG_ITEM_CONTAINER);
            frameContainer.setId(TAG_ITEM_CONTAINER_ID);
            frameContainer.setLayoutConfig(containerLinlayParams);

            // 创建 Fragment 容器
            StackLayout framePager = new StackLayout(getContext());
            framePager.setTag(TAG_ITEM_PAGER);
            framePager.setId(TAG_ITEM_PAGER_ID);
            framePager.setLayoutConfig(pagerFrameParams);
            Object object = pagerAdapter.createPageInContainer(framePager, i);
            framePager.addComponent((Component) object);
            // 创建菜单标题 TextView
            Text tvHint = new Text(getContext());
            tvHint.setTag(TAG_ITEM_HINT);
            tvHint.setId(TAG_ITEM_HINT_ID);
            tvHint.setLayoutConfig(hintLinLayParams);

            frameContainer.addComponent(framePager);
            smItemLayout.addComponent(frameContainer);
            smItemLayout.addComponent(tvHint);
            spinMenuLayout.addComponent(smItemLayout);

            pagerObjects.add(object);
            smItemLayoutList.add(smItemLayout);
        }
        pagerAdapter.onUpdateFinished(spinMenuLayout);
    }

    public void openMenu() {
        if (menuState == MENU_STATE_CLOSED || System.currentTimeMillis() - menuStateUpdateTime > 1000) {
            spinMenuAnimator.openMenuAnimator();
        }
    }

    public void closeMenu(SMItemLayout chooseItemLayout) {
        if (menuState == MENU_STATE_OPENED) {
            spinMenuAnimator.closeMenuAnimator(chooseItemLayout);
        }
    }

    public int getMenuState() {
        return menuState;
    }

    public void updateMenuState(int state) {
        menuStateUpdateTime = System.currentTimeMillis();
        menuState = state;
    }

    public void setEnableGesture(boolean enable) {
        enableGesture = enable;
    }

    public void setMenuItemScaleValue(float scaleValue) {
        scaleRatio = scaleValue;
    }

    public void setHintTextSize(int textSize) {
        hintTextSize = textSize;
    }

    public void setHintTextColor(int textColor) {
        hintTextColor = textColor;
    }

    public void setHintTextStrList(List<String> hintTextList) {
        hintStrList = hintTextList;
    }

    public void setOnSpinMenuStateChangeListener(OnSpinMenuStateChangeListener listener) {
        onSpinMenuStateChangeListener = listener;
    }

    public float getScaleRatio() {
        return scaleRatio;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (enableGesture) {
            gestureDetector.onTouchEvent(touchEvent);
            return true;
        }
        return false;
    }

    private int dp2px(float dp) {
        return (int) (getResourceManager().getDeviceCapability().screenDensity / 160 * dp);
    }

    @Override
    public void onRefreshed(Component component) {
        if (init && smItemLayoutList.size() > 0) {
            // 根据 scaleRatio 去调整菜单中 item 视图的整体大小
            int pagerWidth = (int) (getEstimatedWidth() * scaleRatio);
            int pagerHeight = (int) (getEstimatedHeight() * scaleRatio);
            SMItemLayout.LayoutConfig containerLayoutParams = new SMItemLayout.LayoutConfig(pagerWidth, pagerHeight);
            SMItemLayout smItemLayout;
            StackLayout frameContainer;
            Text tvHint;
            for (int i = 0; i < smItemLayoutList.size(); i++) {
                smItemLayout = smItemLayoutList.get(i);
                frameContainer = (StackLayout) smItemLayout.findComponentById(TAG_ITEM_CONTAINER_ID);
                frameContainer.setLayoutConfig(containerLayoutParams);
                StackLayout pagerLayout = (StackLayout) smItemLayout.findComponentById(TAG_ITEM_PAGER_ID);
                if (i == 0) { // 初始菜单的时候，默认显示第一个 Fragment
                    // 先移除第一个包含 Fragment 的布局
                    frameContainer.removeComponent(pagerLayout);

                    // 创建一个用来占位的 StackLayout
                    StackLayout holderLayout = new StackLayout(getContext());
                    DirectionalLayout.LayoutConfig pagerLinLayParams = new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
                    holderLayout.setLayoutConfig(pagerLinLayParams);

                    // 将占位的 StackLayout 添加到布局中的 frameContainer 中
                    frameContainer.addComponent(holderLayout, 0);

                    // 添加 第一个包含 Fragment 的布局添加到 SpinMenu 中
                    StackLayout.LayoutConfig pagerFrameParams = new StackLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
                    pagerLayout.setLayoutConfig(pagerFrameParams);
                    addComponent(pagerLayout);
                } else {
                    StackLayout.LayoutConfig pagerFrameParams = new StackLayout.LayoutConfig(getEstimatedWidth(), getEstimatedHeight());
                    pagerLayout.setLayoutConfig(pagerFrameParams);
                    pagerLayout.setScale(scaleRatio, scaleRatio);
                    pagerLayout.setTranslation((int) (-getEstimatedWidth() * (1 - scaleRatio) / 2), (int) (-getEstimatedHeight() * (1 - scaleRatio) / 2));
                    ClickUtils.setChildClickable(pagerLayout, false);
                }

                // 显示标题
                if (hintStrList != null && !hintStrList.isEmpty() && i < hintStrList.size()) {
                    tvHint = (Text) smItemLayout.findComponentById(TAG_ITEM_HINT_ID);
                    tvHint.setText(hintStrList.get(i));
                    tvHint.setTextSize(hintTextSize);
                    tvHint.setTextColor(new Color(hintTextColor));
                }

                // 位于菜单中当前显示 Fragment 两边的 SMItemlayout 左右移动 TRAN_SKNEW_VALUE 个距离
                if (spinMenuLayout.getSelectedPosition() + 1 == i
                        || (spinMenuLayout.isCyclic()
                        && spinMenuLayout.getMenuItemCount() - i == spinMenuLayout.getSelectedPosition() + 1)) { // 右侧 ItemMenu
                    smItemLayout.setTranslationX(TRAN_SKNEW_VALUE);
                } else if (spinMenuLayout.getSelectedPosition() - 1 == i
                        || (spinMenuLayout.isCyclic()
                        && spinMenuLayout.getMenuItemCount() - i == 1)) { // 左侧 ItemMenu
                    smItemLayout.setTranslationX(-TRAN_SKNEW_VALUE);
                } else {
                    smItemLayout.setTranslationX(0);
                }
            }
            spinMenuAnimator = new SpinMenuAnimator(this, spinMenuLayout, onSpinMenuStateChangeListener);
            init = false;
        }
    }
}
